package com.gitee.hermer.engine.jars.core.execute.manage.impl;

import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import com.gitee.hermer.boot.jee.commons.verify.Assert;
import com.gitee.hermer.engine.jars.core.context.IEngineAppContext;
import com.gitee.hermer.engine.jars.core.context.domain.EngineAppInfoContext;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteCallable;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteRunnable;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteThread.LifeCycle;
import com.gitee.hermer.engine.jars.core.execute.IEngineExecuteSection;
import com.gitee.hermer.engine.jars.core.execute.domain.EngineResponseBody;
import com.gitee.hermer.engine.jars.core.execute.domain.ExecuteParamsInfo;
import com.gitee.hermer.engine.jars.core.execute.manage.IEngineExecutePoolManager;
import com.gitee.hermer.engine.jars.dependent.thread.pool.IThreadPoolManage;
import com.gitee.hermer.engine.jars.dependent.thread.pool.callback.CallableResult;

@Component
@ComponentScan("com.gitee.hermer.engine.jars.dependent.thread.pool")
public class EngineExecuteManageImpl implements IEngineExecutePoolManager,ApplicationContextAware{

	@Autowired
	private IThreadPoolManage poolManage;

	@Autowired
	private IEngineAppContext appContextService;
	
	private ApplicationContext applicationContext;

	@Override
	public void executeAsyn(EngineExecuteRunnable runnable) throws Throwable {
		Assert.notNull(runnable);
		poolManage.executeAsyn(runnable);
	}
	@Override
	public void afterPropertiesSet() throws Exception {

	}

	@Override
	public void destroy() throws Exception {
		poolManage.destroy();
	}
	@Override
	public <V> void executeAsyn(EngineExecuteCallable<V> runnable,CallableResult<V> callableResult) throws Throwable {
		Assert.notNull(runnable);
		poolManage.executeAsyn(runnable,callableResult);
	}
	@Override
	public <V> V execute(EngineExecuteCallable<V> runnable) throws Throwable {
		return poolManage.execute(runnable);
	}
	
	protected IEngineExecuteSection[] getExecuteSections(){
		Map<String, IEngineExecuteSection> sections = applicationContext.getBeansOfType(IEngineExecuteSection.class);
		IEngineExecuteSection[] array = new IEngineExecuteSection[]{};
		if(sections != null && !sections.isEmpty()){
			return sections.values().toArray(array);
		}else{
			return array;
		}
	}
	
	
	@Override
	public <V> V execute(String projectName, String version, String workMethod, String workVersion, Object[] finArgs)
			throws Throwable {
		EngineAppInfoContext appContext = this.appContextService.getEnableAppModelContext(projectName, workVersion);
		IEngineExecuteSection[] sections = getExecuteSections();
		try{
			if(sections != null){
				for (IEngineExecuteSection section : sections) {
					section.begin(appContext);
				}
			}
			return poolManage.execute(new EngineExecuteCallable<V>(appContext.getJobContext(),appContext.getCacheKey(),
					new ExecuteParamsInfo(projectName, version, workMethod, workVersion, finArgs),LifeCycle.AT_WORK) {
				@Override
				public V onExecute() throws Throwable{
					try{
						if(sections != null){
							for (IEngineExecuteSection section : sections) {
								section.beginExecuteThread(this);
							}
						}
						return appJobContext.invokeEngineAppJob(workMethod, workVersion, finArgs);
					}finally {
						if(sections != null){
							for (IEngineExecuteSection section : sections) {
								section.endExecuteThread(this);
							}
						}
					}

				}
			});
		}finally {
			if(sections != null){
				for (IEngineExecuteSection section : sections) {
					section.end(appContext);
				}
			}
		}
	}
	@Override
	public void execute(EngineExecuteRunnable runnable) throws Throwable {
		poolManage.execute(runnable);
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

}
